package com.njuse.seecjvm.runtime;

import com.njuse.seecjvm.runtime.struct.JObject;
import com.njuse.seecjvm.runtime.struct.Slot;
import lombok.Getter;
import lombok.Setter;

import java.math.BigInteger;
import java.util.EmptyStackException;

@Getter
@Setter
public class OperandStack {
    private int top;
    private int maxStackSize;
    private Slot[] slots;

    public OperandStack(int maxStackSize) {
        assert maxStackSize >= 0;
        this.maxStackSize = maxStackSize;
        slots = new Slot[maxStackSize];
        for (int i = 0; i < maxStackSize; i++) slots[i] = new Slot();
        top = 0;
    }

    /**
     * TODO锛氬悜鎿嶄綔鏁版爤椤剁push涓�涓猧nt鍨嬪彉閲�
     *
     * @param value 鍙橀噺鐨勫��
     */
    public void pushInt(int value) {
        if (top >= maxStackSize) throw new StackOverflowError();
        slots[top].setValue(value);
        top++;
    }

    /**
     * TODO锛氫粠鎿嶄綔鏁版爤椤剁pop涓�涓猧nt鍨嬪彉閲�
     *
     * @return 杩斿洖杩欎釜int鐨勫��
     */
    public int popInt() {
    	top--;
    	if (top < 0) throw new EmptyStackException();
    	int ret=slots[top].getValue();
        slots[top] = new Slot();
        return ret;
    }

    public void pushFloat(float value) {
        if (top >= maxStackSize) throw new StackOverflowError();
        slots[top].setValue(Float.floatToIntBits(value));
        top++;
    }

    public float popFloat() {
        top--;
        if (top < 0) throw new EmptyStackException();
        float ret = Float.intBitsToFloat(slots[top].getValue());
        slots[top] = new Slot();
        return ret;
    }

    /**
     * TODO锛氬悜鎿嶄綔鏁版爤椤秔ush涓�涓� long 绫诲瀷鐨勫彉閲�
     *
     * @param value 鍙橀噺鐨勫��
     */
    public void pushLong(long value) {
    	if (top >= maxStackSize) throw new StackOverflowError();
    	slots[top].setValue((int)value);
    	top++;
    	if (top >= maxStackSize) throw new StackOverflowError();
    	slots[top].setValue((int)(value>>32));
    	top++;
    }

    /**
     * TODO锛氫粠鎿嶄綔鏁版爤椤剁pop涓�涓猯ong鍨嬪彉閲�
     *
     * @return 杩斿洖杩欎釜long鐨勫��
     */
    public long popLong() {

    	top--;
    	int high=slots[top].getValue();
    	slots[top] = new Slot();
    	top--;
    	int low=slots[top].getValue();
    	slots[top] = new Slot();
    	return (((long) high) << 32) | ((long) low & 0x0ffffffffL);
    }

    public void pushDouble(double value) {
        pushLong(Double.doubleToLongBits(value));
    }

    /**
     * TODO锛氫粠鎿嶄綔鏁版爤椤剁pop涓�涓猟ouble鍨嬪彉閲�
     *
     * @return 杩斿洖杩欎釜double鐨勫��
     */
    public double popDouble() {
        return Double.longBitsToDouble(popLong());
    }

    public void pushObjectRef(JObject ref) {
        if (top >= maxStackSize) throw new StackOverflowError();
        slots[top].setObject(ref);
        top++;
    }

    public JObject popObjectRef() {
        top--;
        if (top < 0) throw new EmptyStackException();
        JObject ret = slots[top].getObject();
        slots[top] = new Slot();
        return ret;
    }

    public void pushSlot(Slot slot) {
        if (top >= maxStackSize) throw new StackOverflowError();
        slots[top] = slot;
        top++;
    }

    public Slot popSlot() {
        top--;
        if (top < 0) throw new EmptyStackException();
        Slot ret = slots[top];
        slots[top] = new Slot();
        return ret;
    }

}
